import h337 from './heatmap.js';
import * as Cesium from "cesium";
/**
 * 3D热力图类，支持从GeoJSON点数据生成热力图
 */
export class Heatmap3D {
  /**
   * 构造函数
   * @param {Cesium.Viewer} viewer Cesium viewer实例
   * @param {Object} options 配置参数
   * @param {Object} options.geojson GeoJSON数据对象
   * @param {number} options.radius 热力点半径
   * @param {number} options.baseElevation 基础高度
   * @param {Object} options.colorGradient 颜色梯度配置
   */
  constructor(viewer, options = {}) {
    this.viewer = viewer;
    this.options = options;
    this.heatmapState = this._initState(options);

    if (!this._validateGeoJSON(options.geojson)) {
      console.error("无效的GeoJSON数据");
      return;
    }

    this.dataPoints = this._parseGeoJSON(options.geojson);

    if (this.dataPoints.length < 2) {
      console.error("热力图点位不得少于2个！");
      return;
    }

    this.heatmapState.dataPoints = this.dataPoints;
    this._createHeatmap();
  }

  /**
   * 初始化状态
   * @param {Object} options 配置参数
   * @returns {Object} 状态对象
   */
  _initState(options) {
    return {
      viewer: this.viewer,
      options,
      dataPoints: [],
      containerElement: undefined,
      instanceId: Number(`${new Date().getTime()}${Number(Math.random() * 1000).toFixed(0)}`),
      canvasWidth: 200,
      boundingBox: undefined,
      boundingRect: {},
      xAxis: undefined,
      yAxis: undefined,
      xAxisLength: 0,
      yAxisLength: 0,
      baseElevation: options.baseElevation || 0,
      heatmapPrimitive: undefined,
      positionHierarchy: [],
      heatmapInstance: null,
      primitiveType: options.primitiveType || "TRIANGLES"
    };
  }

  /**
   * 验证GeoJSON数据有效性
   * @param {Object} geojson GeoJSON数据
   * @returns {boolean} 是否有效
   */
  _validateGeoJSON(geojson) {
    if (!geojson || geojson.type !== "FeatureCollection") return false;
    if (!geojson.features || geojson.features.length === 0) return false;

    // 检查是否包含点要素
    return geojson.features.some(feature =>
      feature.geometry && feature.geometry.type === "Point"
    );
  }

  /**
   * 解析GeoJSON数据为热力图点数据
   * @param {Object} geojson GeoJSON数据
   * @returns {Array} 热力图点数组
   */
  _parseGeoJSON(geojson) {
    return geojson.features
      .filter(feature =>
        feature.geometry && feature.geometry.type === "Point" &&
        feature.geometry.coordinates && feature.geometry.coordinates.length >= 2
      )
      .map(feature => {
        // 默认使用value属性作为热力值，没有则使用1
        const value = feature.properties?.value ?? 1;
        return {
          lnglat: [feature.geometry.coordinates[0], feature.geometry.coordinates[1]],
          value: value
        };
      });
  }

  /**
   * 创建热力图
   */
  _createHeatmap() {
    this._createHeatmapContainer();
    this._initHeatmapInstance();
    this._initializeHeatmap();
  }

  /**
   * 创建热力图容器
   */
  _createHeatmapContainer() {
    this.heatmapState.containerElement = document.createElement("div");
    this.heatmapState.containerElement.id = `heatmap-${this.heatmapState.instanceId}`;
    this.heatmapState.containerElement.className = `heatmap`;
    this.heatmapState.containerElement.style.width = `${this.heatmapState.canvasWidth}px`;
    this.heatmapState.containerElement.style.height = `${this.heatmapState.canvasWidth}px`;
    this.heatmapState.containerElement.style.position = "absolute";
    this.heatmapState.containerElement.style.display = "none";

    const mapContainer = document.getElementById(this.viewer.container.id);
    mapContainer.appendChild(this.heatmapState.containerElement);
  }

  /**
   * 初始化热力图实例
   */
  _initHeatmapInstance() {
    const heatmapConfig = {
      container: document.getElementById(`heatmap-${this.heatmapState.instanceId}`),
      radius: this.options.radius || 20,
      maxOpacity: 0.7,
      minOpacity: 0,
      blur: 0.75,
      gradient: this.options.colorGradient || {
        ".1": "blue",
        ".5": "yellow",
        ".7": "red",
        ".99": "white",
      },
    };

    this.heatmapState.heatmapInstance = h337.create(heatmapConfig);

    // 添加willReadFrequently优化
    const canvas = this.heatmapState.containerElement.querySelector('canvas');
    if (canvas) {
      canvas.willReadFrequently = true;
    }
  }

  /**
   * 初始化热力图数据和渲染
   */
  _initializeHeatmap() {
    // 转换经纬度为笛卡尔坐标
    for (const [index, dataPoint] of this.heatmapState.dataPoints.entries()) {
      const cartesianPosition = Cesium.Cartesian3.fromDegrees(
        dataPoint.lnglat[0],
        dataPoint.lnglat[1],
        0
      );
      this.heatmapState.positionHierarchy.push(cartesianPosition);
    }

    // 计算边界框
    this._computeBoundingBox(this.heatmapState.positionHierarchy);

    // 标准化坐标并添加数据
    const heatmapPoints = this.heatmapState.positionHierarchy.map(
      (position, index) => {
        const normalizedCoords = this._computeNormalizedCoordinates(position);
        return {
          x: normalizedCoords.x,
          y: normalizedCoords.y,
          value: this.heatmapState.dataPoints[index].value,
        };
      }
    );

    // 修改：使用setData替代addData，并计算max/min值
    const values = heatmapPoints.map(p => p.value);
    const minValue = Math.min(...values);
    const maxValue = Math.max(...values);
    this.heatmapState.heatmapInstance.setData({
      min: minValue,
      max: maxValue,
      data: heatmapPoints
    });

    // 创建几何体并添加到场景
    const geometryInstance = new Cesium.GeometryInstance({
      geometry: this._createHeatmapGeometry(),
    });

    this.heatmapState.heatmapPrimitive = this.viewer.scene.primitives.add(
      new Cesium.Primitive({
        geometryInstances: geometryInstance,
        appearance: new Cesium.MaterialAppearance({
          material: new Cesium.Material({
            fabric: {
              type: "Image",
              uniforms: {
                image: this.heatmapState.heatmapInstance.getDataURL(),
              },
            },


          }),
          vertexShaderSource: `
    in vec3 position3DHigh;
    in vec3 position3DLow;
    in vec2 st;
    in float batchId;
    uniform sampler2D image_0; 
    out vec3 v_positionEC;
    out vec2 v_st; 
    // 添加法线变量声明以匹配片段着色器
    out vec3 v_normalEC;
    void main(){
        vec4 p = czm_computePosition();
        v_positionEC = (czm_modelViewRelativeToEye * p).xyz;
        vec4 positionWC = czm_inverseModelView * vec4(v_positionEC, 1.0);
        v_st = st; 
        vec4 color = texture(image_0, v_st); 
        vec3 upDir = normalize(positionWC.xyz); 
        p += vec4(color.r * upDir * 1000.0, 0.0); 
        // 计算并传递法线
        v_normalEC = normalize(czm_normal * vec3(0.0, 0.0, 1.0));
        gl_Position = czm_modelViewProjectionRelativeToEye * p; 
    }`,
          translucent: true,
          flat: true,
        }),
        asynchronous: false,
      })
    );
    this.heatmapState.heatmapPrimitive.id = "heatmap3d";
  }

  /**
   * 计算边界框
   * @param {Array} positions 位置数组
   */
  _computeBoundingBox(positions) {
    if (!positions) return;

    const boundingSphere = Cesium.BoundingSphere.fromPoints(
      positions,
      new Cesium.BoundingSphere()
    );
    const centerPoint = boundingSphere.center;
    const sphereRadius = boundingSphere.radius;

    const modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
      centerPoint.clone()
    );
    const yAxisVector = new Cesium.Cartesian3(0, 1, 0);

    const boundingVertices = [];
    for (let angle = 45; angle <= 360; angle += 90) {
      const rotationMatrix = Cesium.Matrix3.fromRotationZ(
        Cesium.Math.toRadians(angle),
        new Cesium.Matrix3()
      );
      let rotatedYAxis = Cesium.Matrix3.multiplyByVector(
        rotationMatrix,
        yAxisVector,
        new Cesium.Cartesian3()
      );
      rotatedYAxis = Cesium.Cartesian3.normalize(
        rotatedYAxis,
        new Cesium.Cartesian3()
      );
      const scaledVector = Cesium.Cartesian3.multiplyByScalar(
        rotatedYAxis,
        sphereRadius,
        new Cesium.Cartesian3()
      );
      const vertex = Cesium.Matrix4.multiplyByPoint(
        modelMatrix,
        scaledVector.clone(),
        new Cesium.Cartesian3()
      );

      boundingVertices.push(vertex);
    }

    const coordinates = this._cartesiansToLnglats(boundingVertices);
    let minLatitude = Number.MAX_VALUE,
      maxLatitude = Number.MIN_VALUE,
      minLongitude = Number.MAX_VALUE,
      maxLongitude = Number.MIN_VALUE;
    const vertexCount = boundingVertices.length;

    coordinates.forEach((coordinate) => {
      if (coordinate[0] < minLongitude) minLongitude = coordinate[0];
      if (coordinate[0] > maxLongitude) maxLongitude = coordinate[0];
      if (coordinate[1] < minLatitude) minLatitude = coordinate[1];
      if (coordinate[1] > maxLatitude) maxLatitude = coordinate[1];
    });

    const latitudeRange = maxLatitude - minLatitude;
    const longitudeRange = maxLongitude - minLongitude;

    this.heatmapState.boundingRect = {
      minLatitude: minLatitude - latitudeRange / vertexCount,
      maxLatitude: maxLatitude + latitudeRange / vertexCount,
      minLongitude: minLongitude - longitudeRange / vertexCount,
      maxLongitude: maxLongitude + longitudeRange / vertexCount,
    };

    this.heatmapState.boundingBox = {
      leftTop: Cesium.Cartesian3.fromDegrees(
        this.heatmapState.boundingRect.minLongitude,
        this.heatmapState.boundingRect.maxLatitude
      ),
      leftBottom: Cesium.Cartesian3.fromDegrees(
        this.heatmapState.boundingRect.minLongitude,
        this.heatmapState.boundingRect.minLatitude
      ),
      rightTop: Cesium.Cartesian3.fromDegrees(
        this.heatmapState.boundingRect.maxLongitude,
        this.heatmapState.boundingRect.maxLatitude
      ),
      rightBottom: Cesium.Cartesian3.fromDegrees(
        this.heatmapState.boundingRect.maxLongitude,
        this.heatmapState.boundingRect.minLatitude
      ),
    };

    this.heatmapState.xAxis = Cesium.Cartesian3.subtract(
      this.heatmapState.boundingBox.rightTop,
      this.heatmapState.boundingBox.leftTop,
      new Cesium.Cartesian3()
    );
    this.heatmapState.xAxis = Cesium.Cartesian3.normalize(
      this.heatmapState.xAxis,
      new Cesium.Cartesian3()
    );
    this.heatmapState.yAxis = Cesium.Cartesian3.subtract(
      this.heatmapState.boundingBox.leftBottom,
      this.heatmapState.boundingBox.leftTop,
      new Cesium.Cartesian3()
    );
    this.heatmapState.yAxis = Cesium.Cartesian3.normalize(
      this.heatmapState.yAxis,
      new Cesium.Cartesian3()
    );
    this.heatmapState.xAxisLength = Cesium.Cartesian3.distance(
      this.heatmapState.boundingBox.rightTop,
      this.heatmapState.boundingBox.leftTop
    );
    this.heatmapState.yAxisLength = Cesium.Cartesian3.distance(
      this.heatmapState.boundingBox.leftBottom,
      this.heatmapState.boundingBox.leftTop
    );
  }

  /**
   * 计算标准化坐标
   * @param {Cesium.Cartesian3} position 位置
   * @returns {Object} 标准化坐标
   */
  _computeNormalizedCoordinates(position) {
    if (!position) return;

    const cartographic = Cesium.Cartographic.fromCartesian(position.clone());
    cartographic.height = 0;
    position = Cesium.Cartographic.toCartesian(cartographic.clone());

    const originVector = Cesium.Cartesian3.subtract(
      position.clone(),
      this.heatmapState.boundingBox.leftTop,
      new Cesium.Cartesian3()
    );
    const xOffset = Cesium.Cartesian3.dot(originVector, this.heatmapState.xAxis);
    const yOffset = Cesium.Cartesian3.dot(originVector, this.heatmapState.yAxis);

    return {
      x: Number((xOffset / this.heatmapState.xAxisLength) * this.heatmapState.canvasWidth).toFixed(0),
      y: Number((yOffset / this.heatmapState.yAxisLength) * this.heatmapState.canvasWidth).toFixed(0),
    };
  }

  /**
   * 创建热力图几何体
   * @returns {Cesium.Geometry} 几何体
   */
  _createHeatmapGeometry() {
    const meshData = this._generateMeshData();
    return new Cesium.Geometry({
      attributes: new Cesium.GeometryAttributes({
        position: new Cesium.GeometryAttribute({
          componentDatatype: Cesium.ComponentDatatype.DOUBLE,
          componentsPerAttribute: 3,
          values: meshData.positions,
        }),
        st: new Cesium.GeometryAttribute({
          componentDatatype: Cesium.ComponentDatatype.FLOAT,
          componentsPerAttribute: 2,
          values: new Float32Array(meshData.textureCoords),
        }),
      }),
      indices: new Uint16Array(meshData.indices),
      primitiveType: Cesium.PrimitiveType[this.heatmapState.primitiveType],
      boundingSphere: Cesium.BoundingSphere.fromVertices(meshData.positions),
    });
  }

  /**
   * 生成网格数据
   * @returns {Object} 网格数据
   */
  _generateMeshData() {
    const gridWidth = this.heatmapState.canvasWidth || 200;
    const gridHeight = this.heatmapState.canvasWidth || 200;
    const { maxLongitude, maxLatitude, minLongitude, minLatitude } = this.heatmapState.boundingRect;

    const longitudeStep = (maxLongitude - minLongitude) / gridWidth;
    const latitudeStep = (maxLatitude - minLatitude) / gridHeight;
    const positions = [];
    const textureCoords = [];
    const indices = [];

    for (let i = 0; i < gridWidth; i++) {
      const currentLongitude = minLongitude + longitudeStep * i;

      for (let j = 0; j < gridHeight; j++) {
        const currentLatitude = minLatitude + latitudeStep * j;
        const heatValue = this.heatmapState.heatmapInstance.getValueAt({
          x: i,
          y: j,
        }) || 0;
        const cartesian3 = Cesium.Cartesian3.fromDegrees(
          currentLongitude,
          currentLatitude,
          this.heatmapState.baseElevation + heatValue
        );
        positions.push(cartesian3.x, cartesian3.y, cartesian3.z);
        textureCoords.push(i / gridWidth, j / gridHeight);

        if (j !== gridHeight - 1 && i !== gridWidth - 1) {
          indices.push(
            i * gridHeight + j,
            i * gridHeight + j + 1,
            (i + 1) * gridHeight + j
          );
          indices.push(
            (i + 1) * gridHeight + j,
            (i + 1) * gridHeight + j + 1,
            i * gridHeight + j + 1
          );
        }
      }
    }

    return { positions, textureCoords, indices };
  }

  /**
   * 笛卡尔坐标转经纬度
   * @param {Array} cartesians 笛卡尔坐标数组
   * @returns {Array} 经纬度数组
   */
  _cartesiansToLnglats(cartesians) {
    if (!cartesians || cartesians.length < 1) return [];

    return cartesians.map(cartesian => this._cartesianToLnglat(cartesian));
  }

  /**
   * 单个笛卡尔坐标转经纬度
   * @param {Cesium.Cartesian3} cartesian 笛卡尔坐标
   * @returns {Array} 经纬度数组
   */
  _cartesianToLnglat(cartesian) {
    if (!cartesian) return [];

    const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
    const latitude = Cesium.Math.toDegrees(cartographic.latitude);
    const longitude = Cesium.Math.toDegrees(cartographic.longitude);
    const height = cartographic.height;

    return [longitude, latitude, height];
  }

  /**
   * 销毁热力图
   */
  destroy() {
    // 移除容器元素
    const containerElement = document.getElementById(`heatmap-${this.heatmapState.instanceId}`);
    if (containerElement) containerElement.remove();

    // 移除primitive
    if (this.heatmapState.heatmapPrimitive) {
      this.viewer.scene.primitives.remove(this.heatmapState.heatmapPrimitive);
      this.heatmapState.heatmapPrimitive = undefined;
    }
  }
}

// // 初始化Cesium Viewer
// const DOM = document.getElementById("box");
// const viewer = new Cesium.Viewer(DOM, {
//   animation: false,
//   baseLayerPicker: false,
//   baseLayer: Cesium.ImageryLayer.fromProviderAsync(
//     Cesium.ArcGisMapServerImageryProvider.fromUrl(
//       "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer"
//     )
//   ),
//   fullscreenButton: false,
//   timeline: false,
//   infoBox: false,
// });

// // 隐藏Cesium版权信息
// viewer._cesiumWidget._creditContainer.style.display = "none";

// // 使用示例 - 从GeoJSON加载数据
// async function loadGeoJSONAndCreateHeatmap() {
//   try {
//     // 这里替换为你的GeoJSON数据URL或直接使用GeoJSON对象
//     // const response = await fetch('path/to/your/data.geojson');
//     // const geojson = await response.json();

//     // 示例GeoJSON数据
//     const geojson = {
//       "type": "FeatureCollection",
//       "features": [
//         // 生成一些示例点（实际使用时替换为你的数据）
//         ...Array(50).fill("").map(() => ({
//           "type": "Feature",
//           "geometry": {
//             "type": "Point",
//             "coordinates": [
//               116.46 + Math.random() * 0.1 * (Math.random() > 0.5 ? 1 : -1),
//               39.92 + Math.random() * 0.1 * (Math.random() > 0.5 ? 1 : -1)
//             ]
//           },
//           "properties": {
//             "value": 1000 * Math.random()
//           }
//         }))
//       ]
//     };

//     // 创建3D热力图
//     const heatmap = new Heatmap3D(viewer, {
//       geojson: geojson,
//       radius: 20,
//       baseElevation: 0,
//       colorGradient: {
//         ".1": "blue",
//         ".5": "yellow",
//         ".7": "red",
//         ".99": "white"
//       }
//     });

//     // 调整视角到热力图区域
//     if (geojson.features.length > 0) {
//       const firstPoint = geojson.features[0].geometry.coordinates;
//       viewer.camera.flyTo({
//         destination: Cesium.Cartesian3.fromDegrees(firstPoint[0], firstPoint[1], 2000)
//       });
//     }

//     return heatmap;
//   } catch (error) {
//     console.error("加载GeoJSON失败:", error);
//   }
// }

// // 加载并创建热力图
// loadGeoJSONAndCreateHeatmap();